import { Injectable, Logger } from '@nestjs/common';
import * as winston from 'winston';
import type {
  LoggingInterface,
  StructuredLoggingInterface,
  StructuredLogData,
  RequestLogData,
  ResponseLogData,
  DatabaseQueryLogData,
  CacheOperationLogData,
  ExternalApiCallLogData,
  BusinessEventLogData,
  UserLogData,
  LoggingConfig,
} from '../../logging/logging.interface';
import { LogLevel } from '../../logging/logging.interface';

/**
 * Winston 服务
 * 基于 NestJS 官方示例实现
 * 参考: https://docs.nestjs.cn/fundamentals/dependency-injection
 * 对应 Java: 日志服务
 */
@Injectable()
export class WinstonService
  implements LoggingInterface, StructuredLoggingInterface
{
  private readonly logger = new Logger(WinstonService.name);
  private winston: winston.Logger;
  private currentLevel: LogLevel = LogLevel.INFO;

  constructor(
    private readonly config: LoggingConfig = {
      level: LogLevel.INFO,
      format: 'json',
      timestamp: true,
      colorize: false,
      prettyPrint: false,
      silent: false,
      exitOnError: false,
      transports: [{ type: 'console', level: LogLevel.INFO }],
      defaultMeta: {},
      context: 'WinstonService',
    },
  ) {
    this.initializeWinston();
  }

  private initializeWinston() {
    const transports: winston.transport[] = [];

    // 控制台传输器
    if (this.config.transports.some((t) => t.type === 'console')) {
      const consoleTransport = new winston.transports.Console({
        level: this.config.level,
        format: this.getFormat('console'),
      });
      transports.push(consoleTransport);
    }

    // 文件传输器
    const fileTransports = this.config.transports.filter(
      (t) => t.type === 'file',
    );
    for (const fileTransport of fileTransports) {
      const transport = new winston.transports.File({
        level: fileTransport.level || this.config.level,
        filename: fileTransport.options?.filename || 'app.log',
        format: this.getFormat('file'),
        ...fileTransport.options,
      });
      transports.push(transport);
    }

    // HTTP传输器
    const httpTransports = this.config.transports.filter(
      (t) => t.type === 'http',
    );
    for (const httpTransport of httpTransports) {
      const transport = new winston.transports.Http({
        level: httpTransport.level || this.config.level,
        host: httpTransport.options?.host || 'localhost',
        port: httpTransport.options?.port || 80,
        path: httpTransport.options?.path || '/logs',
        ...httpTransport.options,
      });
      transports.push(transport);
    }

    // 流传输器
    const streamTransports = this.config.transports.filter(
      (t) => t.type === 'stream',
    );
    for (const streamTransport of streamTransports) {
      const transport = new winston.transports.Stream({
        level: streamTransport.level || this.config.level,
        stream: streamTransport.options?.stream,
        format: this.getFormat('stream'),
        ...streamTransport.options,
      });
      transports.push(transport);
    }

    this.winston = winston.createLogger({
      level: this.config.level,
      format: this.getFormat('default'),
      defaultMeta: this.config.defaultMeta,
      transports,
      silent: this.config.silent,
      exitOnError: this.config.exitOnError,
    });
  }

  private getFormat(type: string): winston.Logform.Format {
    const formats: winston.Logform.Format[] = [];

    // 时间戳
    if (this.config.timestamp) {
      formats.push(winston.format.timestamp());
    }

    // 日志级别
    // winston.format.level() 在新版本中已移除

    // 消息格式
    if (this.config.format === 'json') {
      formats.push(winston.format.json());
    } else if (this.config.format === 'simple') {
      formats.push(winston.format.simple());
    } else {
      formats.push(
        winston.format.printf(
          ({ timestamp, level, message, context, ...meta }) => {
            const contextStr = context ? `[${context}] ` : '';
            const metaStr =
              Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
            return `${timestamp} [${level}] ${contextStr}${message}${metaStr}`;
          },
        ),
      );
    }

    // 颜色
    if (this.config.colorize && type === 'console') {
      formats.push(winston.format.colorize());
    }

    // 美化打印
    if (this.config.prettyPrint) {
      formats.push(winston.format.prettyPrint());
    }

    return winston.format.combine(...formats);
  }

  // ==================== 基础日志接口 ====================

  /**
   * 记录调试日志
   */
  debug(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.debug(message, { context, ...meta });
  }

  /**
   * 记录信息日志
   */
  info(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.info(message, { context, ...meta });
  }

  /**
   * 记录警告日志
   */
  warn(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.warn(message, { context, ...meta });
  }

  /**
   * 记录错误日志
   */
  error(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.error(message, { context, ...meta });
  }

  /**
   * 记录致命错误日志
   */
  fatal(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.error(message, { context, level: 'fatal', ...meta });
  }

  /**
   * 记录日志
   */
  log(
    level: LogLevel,
    message: string,
    context?: string,
    meta?: Record<string, any>,
  ): void {
    this.winston.log(level, message, { context, ...meta });
  }

  /**
   * 设置日志级别
   */
  setLevel(level: LogLevel): void {
    this.currentLevel = level;
    this.winston.level = level;
  }

  /**
   * 获取当前日志级别
   */
  getLevel(): LogLevel {
    return this.currentLevel;
  }

  /**
   * 创建子日志器
   */
  child(context: string): LoggingInterface {
    const childLogger = this.winston.child({ context });
    return new WinstonChildService(childLogger, context);
  }

  // ==================== 结构化日志接口 ====================

  /**
   * 记录结构化日志
   */
  logStructured(
    level: LogLevel,
    message: string,
    structuredData: StructuredLogData,
  ): void {
    this.winston.log(level, message, structuredData);
  }

  /**
   * 记录请求日志
   */
  logRequest(
    request: RequestLogData,
    response: ResponseLogData,
    duration: number,
  ): void {
    const logData = {
      type: 'http_request',
      request: {
        method: request.method,
        url: request.url,
        headers: this.sanitizeHeaders(request.headers),
        body: this.sanitizeBody(request.body),
        query: request.query,
        params: request.params,
        ip: request.ip,
        userAgent: request.userAgent,
        userId: request.userId,
        sessionId: request.sessionId,
      },
      response: {
        statusCode: response.statusCode,
        headers: this.sanitizeHeaders(response.headers),
        body: this.sanitizeBody(response.body),
        size: response.size,
      },
      duration,
      timestamp: new Date().toISOString(),
    };

    this.winston.info('HTTP Request', logData);
  }

  /**
   * 记录数据库查询日志
   */
  logDatabaseQuery(
    query: DatabaseQueryLogData,
    duration: number,
    result?: any,
  ): void {
    const logData = {
      type: 'database_query',
      query: {
        operation: query.operation,
        table: query.table,
        query: query.query,
        params: query.params,
        connection: query.connection,
        transaction: query.transaction,
      },
      duration,
      result: this.sanitizeResult(result),
      timestamp: new Date().toISOString(),
    };

    this.winston.info('Database Query', logData);
  }

  /**
   * 记录缓存操作日志
   */
  logCacheOperation(
    operation: CacheOperationLogData,
    hit: boolean,
    duration: number,
  ): void {
    const logData = {
      type: 'cache_operation',
      operation: {
        operation: operation.operation,
        key: operation.key,
        ttl: operation.ttl,
        size: operation.size,
      },
      hit,
      duration,
      timestamp: new Date().toISOString(),
    };

    this.winston.info('Cache Operation', logData);
  }

  /**
   * 记录外部API调用日志
   */
  logExternalApiCall(
    apiCall: ExternalApiCallLogData,
    response: any,
    duration: number,
  ): void {
    const logData = {
      type: 'external_api_call',
      apiCall: {
        service: apiCall.service,
        endpoint: apiCall.endpoint,
        method: apiCall.method,
        headers: this.sanitizeHeaders(apiCall.headers),
        body: this.sanitizeBody(apiCall.body),
        timeout: apiCall.timeout,
      },
      response: this.sanitizeResponse(response),
      duration,
      timestamp: new Date().toISOString(),
    };

    this.winston.info('External API Call', logData);
  }

  /**
   * 记录业务事件日志
   */
  logBusinessEvent(
    event: BusinessEventLogData,
    user?: UserLogData,
    meta?: Record<string, any>,
  ): void {
    const logData = {
      type: 'business_event',
      event: {
        event: event.event,
        action: event.action,
        resource: event.resource,
        resourceId: event.resourceId,
        data: event.data,
        result: event.result,
      },
      user: user
        ? {
            id: user.id,
            username: user.username,
            email: user.email,
            role: user.role,
            permissions: user.permissions,
          }
        : undefined,
      meta,
      timestamp: new Date().toISOString(),
    };

    this.winston.info('Business Event', logData);
  }

  // ==================== 工具方法 ====================

  /**
   * 清理请求头
   */
  private sanitizeHeaders(
    headers: Record<string, string>,
  ): Record<string, string> {
    const sanitized: Record<string, string> = {};
    const sensitiveHeaders = [
      'authorization',
      'cookie',
      'x-api-key',
      'x-auth-token',
    ];

    for (const [key, value] of Object.entries(headers)) {
      if (sensitiveHeaders.includes(key.toLowerCase())) {
        sanitized[key] = '[REDACTED]';
      } else {
        sanitized[key] = value;
      }
    }

    return sanitized;
  }

  /**
   * 清理请求体
   */
  private sanitizeBody(body: any): any {
    if (!body) return body;

    if (typeof body === 'string') {
      try {
        const parsed = JSON.parse(body);
        return this.sanitizeObject(parsed);
      } catch {
        return body;
      }
    }

    if (typeof body === 'object') {
      return this.sanitizeObject(body);
    }

    return body;
  }

  /**
   * 清理对象
   */
  private sanitizeObject(obj: any): any {
    if (!obj || typeof obj !== 'object') return obj;

    const sanitized = { ...obj };
    const sensitiveFields = ['password', 'token', 'secret', 'key', 'auth'];

    for (const field of sensitiveFields) {
      if (sanitized[field]) {
        sanitized[field] = '[REDACTED]';
      }
    }

    return sanitized;
  }

  /**
   * 清理结果
   */
  private sanitizeResult(result: any): any {
    if (!result) return result;

    if (typeof result === 'object') {
      return this.sanitizeObject(result);
    }

    return result;
  }

  /**
   * 清理响应
   */
  private sanitizeResponse(response: any): any {
    if (!response) return response;

    if (typeof response === 'object') {
      return this.sanitizeObject(response);
    }

    return response;
  }

  /**
   * 获取原始 Winston 实例
   */
  getWinston(): winston.Logger {
    return this.winston;
  }

  /**
   * 添加传输器
   */
  addTransport(transport: winston.transport): void {
    this.winston.add(transport);
  }

  /**
   * 移除传输器
   */
  removeTransport(transport: winston.transport): void {
    this.winston.remove(transport);
  }

  /**
   * 清空传输器
   */
  clearTransports(): void {
    this.winston.clear();
  }

  /**
   * 关闭日志器
   */
  async close(): Promise<void> {
    return new Promise((resolve) => {
      this.winston.end(() => {
        resolve();
      });
    });
  }
}

/**
 * Winston 子日志器服务
 */
class WinstonChildService implements LoggingInterface {
  constructor(
    private readonly winston: winston.Logger,
    private readonly context: string,
  ) {}

  debug(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.debug(message, { context: context || this.context, ...meta });
  }

  info(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.info(message, { context: context || this.context, ...meta });
  }

  warn(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.warn(message, { context: context || this.context, ...meta });
  }

  error(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.error(message, { context: context || this.context, ...meta });
  }

  fatal(message: string, context?: string, meta?: Record<string, any>): void {
    this.winston.error(message, {
      context: context || this.context,
      level: 'fatal',
      ...meta,
    });
  }

  log(
    level: LogLevel,
    message: string,
    context?: string,
    meta?: Record<string, any>,
  ): void {
    this.winston.log(level, message, {
      context: context || this.context,
      ...meta,
    });
  }

  setLevel(level: LogLevel): void {
    this.winston.level = level;
  }

  getLevel(): LogLevel {
    return this.winston.level as LogLevel;
  }

  child(context: string): LoggingInterface {
    const childLogger = this.winston.child({ context });
    return new WinstonChildService(childLogger, context);
  }
}
